package miniMax;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Observable;


/**
 * The model
 * 
 * @author tim
 * 
 */
public class TicTacToeFramework extends Observable {

	private static final String FREEFIELD = " ";
	private final int FIELDSIZE = 3;
	private String[][] gameField = new String[FIELDSIZE][FIELDSIZE];
	private static TicTacToeFramework singleTon = null;

	public final void resetGamefield() {
		init();
	}

	public final String[][] getGameField() {
		String[][] gameTMP = new String[FIELDSIZE][FIELDSIZE];
		for (int i = 0; i < gameTMP.length; i++) {
			for (int j = 0; j < gameTMP.length; j++) {
				gameTMP[i][j] = gameField[i][j];
			}
		}
		return gameTMP;
	}

	@Override
	public boolean equals(Object obj) {
		TicTacToeFramework ttt;
		if (obj instanceof TicTacToeFramework) {
			ttt = (TicTacToeFramework) obj;
		} else {
			return false;
		}
		for (int i = 0; i < this.gameField.length; i++) {
			for (int j = 0; j < this.gameField.length; j++) {
				if (!this.gameField[i][j].equals(
						ttt.getGameField()[i][j])) {
					return false;
				}
			}
		}
		return true;

	}

	@Override
	public int hashCode() {
		return Arrays.deepHashCode(gameField);
	}

	public void setGameField(String[][] gameField) {
		this.gameField = gameField;
	}

	public static TicTacToeFramework getTicTacToeFrameWork() {
		if (singleTon == null) {
			singleTon = new TicTacToeFramework();
		}
		return singleTon;
	}

	public TicTacToeFramework() {
		init();
		singleTon = this;

	}

	public void removechar(int id) {
		int[] arr = convertIdToRowCol(id);
		gameField[arr[0]][arr[1]] = FREEFIELD;
	}

	public void init() {
		for (int i = 0; i < gameField.length; i++) {
			for (int j = 0; j < gameField.length; j++) {
				gameField[i][j] = FREEFIELD;
			}
		}
		// gameField[2][0] = "T";
		// gameField[1][0] = "T";
		// gameField[0][0] = "C";
		// gameField[1][2] = "T";
		// gameField[2][1] = "C";
		// gameField[2][1] = "C";
		setChanged();
		notifyObservers();
	}

	private boolean checkFree(final int row, final int column) {
		if (gameField[row][column] == FREEFIELD) {
			return true;
		} else {
			return false;
		}
	}

	private boolean checkBounds(final int row, final int column) {
		if (row < 0 || row > FIELDSIZE) {
			return false;
		}
		if (column < 0 || column > FIELDSIZE) {
			return false;
		}
		return true;
	}

	@Override
	public String toString() {
		print();
		return "";
	}

	public void print() {
		for (int row = 0; row < gameField.length; row++) {
			printLine(row);
			System.out.println("\n-----------");
		}
		System.out.println();
	}

	private void printLine(final int row) {
		for (int i = 0; i < gameField.length; i++) {
			System.out.print(gameField[row][i]);
			if (i < gameField.length - 1) {
				System.out.print(" | ");
			}
		}

	}

	/**
	 * 
	 * @param row
	 * @param col
	 * @return -1 no win, 0 draw, 1 win
	 */

	public final int checkWin(int input) {
		int[] arr = convertIdToRowCol(input);

		boolean rowTrue = checkRow(arr[0]);
		boolean digTrue = checkDig();
		boolean colTrue = checkCol(arr[1]);
		boolean win = rowTrue || digTrue || colTrue;
		int possFieldsize = possFields().size();
		if (!win && possFieldsize == 0) {
			return 0;
		}
		if (!win) {
			return -1;
		}
		return 1;

	}

	private boolean checkCol(final int col) {
		if (gameField[0][col] == FREEFIELD)
			return false;
		return gameField[0][col].equals(gameField[1][col])
				&& gameField[0][col].equals(gameField[2][col]);
	}

	private boolean checkDig() {
		boolean ltr = digLeftToRight();
		boolean rtl = digRightToLeft();
		return ltr || rtl;
	}

	private boolean digRightToLeft() {
		if (gameField[2][0] == FREEFIELD)
			return false;
		return gameField[2][0].equals(gameField[1][1])
				&& gameField[2][0].equals(gameField[0][2]);
	}

	private boolean digLeftToRight() {
		if (gameField[0][0] == FREEFIELD)
			return false;
		return gameField[0][0].equals(gameField[1][1])
				&& gameField[0][0].equals(gameField[2][2]);
	}

	private boolean checkRow(final int row) {
		if (gameField[row][0] == FREEFIELD)
			return false;
		return gameField[row][0].equals(gameField[row][1])
				&& gameField[row][0].equals(gameField[row][2]);
	}

	/**
	 * 
	 * @param row
	 * @param col
	 * @param testFlag
	 * @return -1 for Error, 0 for Win, 1 for correct move
	 */

	public final boolean setChar(final int row, final int col, String String,
			boolean NoTestFlag) {
		boolean inside = checkBounds(row, col);
		boolean isFree = checkFree(row, col);
		if (inside && isFree) {
			gameField[row][col] = String;
			if (NoTestFlag) {
				setChanged();
				notifyObservers();
			}
			// print();
			return true;
		}
		return false;

	}

	public final boolean setCharWithID(int input, String String,
			boolean testFlag) {
		int[] arr = convertIdToRowCol(input);
		return setChar(arr[0], arr[1], String, testFlag);
	}

	private int[] convertIdToRowCol(int input) {
		int[] arr = new int[2];
		if (input == 1) {
			arr[0] = 0;
			arr[1] = 0;
		} else if (input == 2) {
			arr[0] = 0;
			arr[1] = 1;
		} else if (input == 3) {
			arr[0] = 0;
			arr[1] = 2;
		} else if (input == 4) {
			arr[0] = 1;
			arr[1] = 0;
		} else if (input == 5) {
			arr[0] = 1;
			arr[1] = 1;
		} else if (input == 6) {
			arr[0] = 1;
			arr[1] = 2;
		} else if (input == 7) {
			arr[0] = 2;
			arr[1] = 0;
		} else if (input == 8) {
			arr[0] = 2;
			arr[1] = 1;
		} else if (input == 9) {
			arr[0] = 2;
			arr[1] = 2;

		}
		return arr;
	}

	public int returnFieldID(final int row, final int column) {
		if (row == 0) {
			if (column == 0) {
				return row * 3 + 1;
			}
			if (column == 1) {
				return row * 3 + 2;
			}
			if (column == 2) {
				return row * 3 + 3;
			}
		}
		if (row == 1) {
			if (column == 0) {
				return row * 3 + 1;
			}
			if (column == 1) {
				return row * 3 + 2;
			}
			if (column == 2) {
				return row * 3 + 3;
			}
		}
		if (row == 2) {
			if (column == 0) {
				return row * 3 + 1;
			}
			if (column == 1) {
				return row * 3 + 2;
			}
			if (column == 2) {
				return row * 3 + 3;
			}
		}
		return column;
	}

	public final List<Integer> possFields() {
		List<Integer> possFields = new ArrayList<Integer>();
		for (int i = 0; i < gameField.length; i++) {
			for (int j = 0; j < gameField[i].length; j++) {
				if (gameField[i][j] == FREEFIELD) {
					possFields.add(returnFieldID(i, j));
				}
			}
		}
		return possFields;

	}

}
